package com.xph.core.common.util;

import java.util.List;
import java.util.Map;

import org.apache.ibatis.builder.xml.dynamic.ForEachSqlNode;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.mapping.ParameterMode;
import org.apache.ibatis.mapping.ResultMap;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.property.PropertyTokenizer;
import org.apache.ibatis.session.SqlSession;
import org.apache.log4j.Logger;

/**
 * Mybatis sql工具类
 * @author zuo kai
 *
 */
public class MyBatisSql {    
    private static Logger logger = Logger.getLogger(MyBatisSql.class);
    private String sql;//运行期的sql，带?    
    private Object[] parameters;//;//运行期的参数，与?相匹配    
    private Class resultClass;//<select id="XXX" resultType="ZZZ">中的resultType    
   
    public Class getResultClass() {    
        return resultClass;    
    }    
   
    public void setResultClass(Class resultClass) {    
        this.resultClass = resultClass;    
    }    
   
    public void setSql(String sql) {    
        this.sql = sql;    
    }    
   
    public String getSql() {    
        return sql;    
    }    
   
    public void setParameters(Object[] parameters) {    
        this.parameters = parameters;    
    }    
   
    public Object[] getParameters() {    
        return parameters;    
    }    
   
    public MyBatisSql getMyBatisSql(Map map, String mapperId, SqlSession sqlSession)
    {
        MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(mapperId);
           
        BoundSql boundSql = ms.getBoundSql(map);
        
        List<ResultMap> ResultMaps=ms.getResultMaps();    
        if(ResultMaps!=null&&ResultMaps.size()>0){    
            ResultMap ResultMap = ms.getResultMaps().get(0);    
            this.setResultClass(ResultMap.getType());    
        }    
        //获取带?的sql语句
        this.setSql(boundSql.getSql());    

        //按顺序获取参数，并将问号替换成对应参数
        Object parameterObject = boundSql.getParameterObject();
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if(parameterMappings != null)
        {
            Object[] parameterArray = new Object[parameterMappings.size()];
            MetaObject metaObject = parameterObject == null ? null : MetaObject.forObject(parameterObject);
            for (int i = 0; i < parameterMappings.size(); i++)
            {
                ParameterMapping parameterMapping = parameterMappings.get(i);
                //logger.info(parameterMappings.get(i));
                
                if (parameterMapping.getMode() != ParameterMode.OUT)
                {
                    Object value;
                    String propertyName = parameterMapping.getProperty();
                    PropertyTokenizer prop = new PropertyTokenizer(propertyName);
                    if (parameterObject == null)
                    {
                        value = null;
                    }
                    else if (ms.getConfiguration().getTypeHandlerRegistry().hasTypeHandler(parameterObject.getClass()))
                    {
                        value = parameterObject;
                    }
                    else if (boundSql.hasAdditionalParameter(propertyName))
                    {
                        value = boundSql.getAdditionalParameter(propertyName);
                    }
                    else if (propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX)
                            && boundSql.hasAdditionalParameter(prop.getName()))
                    {
                        value = boundSql.getAdditionalParameter(prop.getName());
                        if (value != null)
                        {
                            value = MetaObject.forObject(value).getValue(
                                    propertyName.substring(prop.getName().length()));
                        }
                    }
                    else
                    {
                        value = metaObject == null ? null : metaObject.getValue(propertyName);
                    }
                    parameterArray[i] = value;
                    
                    //如果是属性不是集合
                    if(!propertyName.startsWith(ForEachSqlNode.ITEM_PREFIX))
                    {
                        Object type = map.get(propertyName).getClass();
                        if(type.equals(String.class))
                        {
                            //将字符串参数两边加上单引号
                            this.setSql(this.getSql().replaceFirst("\\?", "'" + value.toString() + "'"));
                        }
                        else 
                        {
                            this.setSql(this.getSql().replaceFirst("\\?", value.toString()));
                        }
                    }
                    else //如果属性为集合
                    {
                        this.setSql(this.getSql().replaceFirst("\\?", value.toString()));
                    }
                }
            }
            this.setParameters(parameterArray);
        }
        //logger.info(boundSql.getSql().toString());
        return this;
    }
    
}

